package cn.cxyxj.study.webflux03;

import cn.cxyxj.study.webflux03.constant.Constant;
import cn.cxyxj.study.webflux03.constant.RedisKey;
import cn.cxyxj.study.webflux03.entity.SysUser;
import cn.cxyxj.study.webflux03.entity.SysUserDetails;
import cn.cxyxj.study.webflux03.utils.JWTUtil;
import cn.cxyxj.study.webflux03.utils.RedisUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.UUID;

/**
 * @author cxyxj
 */
@Component
public class CustomAuthenticationSuccessHandler implements ServerAuthenticationSuccessHandler {

    private Logger logger = LoggerFactory.getLogger(CustomAuthenticationSuccessHandler.class);

    @Override
    public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
        ServerWebExchange exchange = webFilterExchange.getExchange();
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().add("Content-Type", "application/json; charset=UTF-8");
        Object principal = authentication.getPrincipal();
        SysUserDetails userInfo = (SysUserDetails) principal;
        SysUser sysUser = userInfo.getSysUser();
        sysUser.setPassword(null);
        String uuidStr = UUID.randomUUID().toString().replace("-", "");
        String token = JWTUtil.generateToken(userInfo,uuidStr);
        // 如下逻辑为：同账号多次登录，只存储最后一次登录产生的token。即同账号同时只能一人处于登录状态
        // key:user-token:1
        String oldTokenStr = RedisUtil.get(String.format(RedisKey.USER_TOKEN,sysUser.getId()));
        // 获取老token，将老token删除
        if (StringUtils.hasLength(oldTokenStr)) {
            RedisUtil.del(String.format(RedisKey.TOKEN, oldTokenStr));
        }
        // 保存到 Redis 中，并设置过期时间
        RedisUtil.set(String.format(RedisKey.TOKEN, uuidStr), JSONObject.toJSONString(principal), Duration.ofDays(Constant.TOKEN_EXPIRATION_TIME));
        RedisUtil.set(String.format(RedisKey.USER_TOKEN,sysUser.getId()), uuidStr, Duration.ofDays(Constant.TOKEN_EXPIRATION_TIME));
        ObjectMapper objectMapper = new ObjectMapper();
        DataBuffer bodyDataBuffer = null;
        try {
            bodyDataBuffer = response.bufferFactory().wrap(objectMapper.writeValueAsBytes(token));
        } catch (JsonProcessingException e) {
            logger.error("JsonProcessingException",e);
        }
        return response.writeWith(Mono.just(bodyDataBuffer));
    }
}